import Vue from 'vue'
import { saveAs } from 'file-saver'
import { DataUri } from '@antv/x6/lib/index'
import Snap from 'snapsvg'
import $ from 'jquery'
var _ = require('lodash')
import { updateGraphFile } from '@/api/draw.js'
import ConfigUtil from '@/utils/graph-utils/configUtil'
import UIUtil from '@/utils/graph-utils/uiUtil'
import { nanoid } from 'nanoid'

export default {
  handleOpen(graph, json) {
    graph.clearCells()
    graph.fromJSON(json)
    graph.scrollToContent()
  },

  handleSave(component, graph, localSave) {
    const self = this
    const currentFile = component.$store.state.graphModule.currentGraphFile
    if (currentFile === null) {
      return
    }
    // 保存时需要将画布还原，否则画面大小可能是错误的数值
    self.handleZoomRestore(graph)
    // 获取graph中所有节点最左边和最上边的位置
    let width = graph.options.width
    let height = graph.options.height
    let x = 0
    let y = 0
    const nodes = graph.getNodes()
    for (const node of nodes) {
      const position = node.position()
      x = Math.min(x, position.x)
      y = Math.min(y, position.y)
    }
    if (x < 0) {
      x -= 50
      width -= x
    }
    if (y < 0) {
      y -= 50
      height -= y
    }
    var jsonContent = JSON.stringify(graph.toJSON(), null, '\t')
    graph.toSVG((dataUri) => {
      if (localSave) {
        self.handleSaveLocal(component, dataUri, jsonContent)
      } else {
        self.handleSaveSql(component, dataUri, jsonContent)
      }
    }, {
      preserveDimensions: {
        width: width,
        height: height
      },
      viewBox: {
        x: x,
        y: y,
        width: width,
        height: height
      },
      copyStyles: false,
      beforeSerialize: (svg) => {
        self.handleBeforeSerialize(component, graph, svg)
      }
    })
  },

  handleSaveSql(component, svgContent, jsonContent) {
    const currentFile = component.$store.state.graphModule.currentGraphFile
    const graphFile = {
      id: currentFile.id,
      name: currentFile.title,
      svgContent: {
        content: svgContent
      },
      jsonContent: {
        content: jsonContent
      }
    }
    updateGraphFile(graphFile).then(response => {
      UIUtil.successMessage('保存图形文件成功')
    })
  },

  handleSaveLocal(component, svgContent, jsonContent) {
    const currentFile = component.$store.state.graphModule.currentGraphFile
    var blob = new Blob([jsonContent], { type: 'text/plaincharset=utf-8' })
    saveAs(blob, currentFile.title + '.txt')
    // 下载svg
    DataUri.downloadDataUri(DataUri.svgToDataUrl(svgContent), currentFile.title + '.svg')
  },

  handleBeforeSerialize(component, graph, svg) {
    const svgElement = Snap(svg)
    // 设置背景色
    const backGround = component.$store.state.graphModule.graphOptions.background.color
    svgElement.attr({
      background: backGround
    })
    // 去掉svg嵌套的g节点
    this.handleGroupElement(svgElement)
    // 处理图形中的连线
    this.handleEdgeElement(graph, svgElement)
    // 去掉class为x6-port的节点
    this.removeElementByClass(svgElement)
    this.updateElementAttr(graph, svgElement)
    this.customizeSvg(component, svgElement, svgElement)
  },

  // 处理原生svg中嵌套的group节点
  handleGroupElement(svgElement) {
    let gElement = svgElement.select('.x6-graph-svg-stage')
    if (gElement) {
      const childrens = gElement.children()
      for (const children of childrens) {
        children.appendTo(svgElement)
      }
    }
    gElement = svgElement.select('.x6-graph-svg-viewport')
    if (gElement) {
      gElement.remove()
    }
  },

  handleEdgeElement(graph, svgElement) {
    // 获取图形中所有的edge
    const edgeElements = svgElement.selectAll('.x6-edge')
    edgeElements.forEach(function(element) {
      const attr = element.attr()
      const pathElements = element.children()
      const edgeId = attr['data-cell-id']
      if (edgeId !== '' && pathElements.length === 2) {
        const dAttr = pathElements[1].attr()['d']
        const styleAttr = pathElements[1].attr()['style']
        const edge = graph.getCell(edgeId)
        if (edge !== null && dAttr !== '') {
          const pointsValue = _.replace(dAttr, /(M )|(L )/g, '')
          const newAttr = _.cloneDeep(attr)
          newAttr.style = styleAttr || 'fill:none;stroke:#7c68fc;stroke-width:2;'
          newAttr.points = pointsValue

          // 新建一个polyline类型
          svgElement.paper.el('polyline', newAttr)
          element.remove()
        }
      }
    })
  },

  removeElementByClass(svgElement) {
    const elements = svgElement.selectAll('.x6-port')
    elements.forEach(function(element) {
      element.remove()
    })
  },

  // 从节点的data属性中过滤掉无用的属性
  filterUnvalidDataAttr(attr) {
    const deep = _.cloneDeep(attr)
    if (deep) {
      const unvalidKeys = ['selector', 'group', 'isPort', 'enableResize',
        'minWidth', 'maxWidth', 'minHeight', 'maxHeight']
      for (const key of unvalidKeys) {
        _.unset(deep, key)
      }
    }
    return deep
  },

  updateElementAttr(graph, element) {
    const attr = element.attr()
    // 如果属性中存在data-cell-id，则为图形中的一个节点元素
    const id = attr['data-cell-id']
    if (id) {
      // 根据id从图中获取节点
      const cell = graph.getCell(id)
      if (cell.data) {
        // 清除data-cell-id属性
        _.set(attr, 'data-cell-id', '')
        element.attr(attr)
        // 设置节点的自定义属性
        element.attr(this.filterUnvalidDataAttr(cell.data))
      }
    } else {
      const childrens = element.children()
      for (const children of childrens) {
        this.updateElementAttr(graph, children)
      }
    }
  },

  customizeSvg(component, element, svgElement) {
    const childrens = element.children()
    for (const children of childrens) {
      const dataShape = children.attr('data-shape')
      const metaType = children.attr('metaType')
      if (!dataShape || !metaType) {
        continue
      }
      if (ConfigUtil.isMeasureNode(metaType)) {
        this.customizeSimpleText(children, svgElement)
      } else if (ConfigUtil.isLineNode(metaType)) {
        // this.customizeLineNode(children, svgElement)
      } else if (ConfigUtil.isFaultNode(metaType)) {
        this.customizeFaultNode(children, svgElement)
      } else if (ConfigUtil.isCustomizeNode(dataShape) && !ConfigUtil.isBusNode(metaType)) {
        this.customizeCommonNode(component, dataShape, children, svgElement)
      } else {
        this.customizeSvg(component, children, svgElement)
      }
    }
  },

  // 自定义处理simpleText节点
  customizeSimpleText(element, svgElement) {
    const attr = element.attr()
    const childrens = element.children()
    for (const children of childrens) {
      if (children.type !== 'text') {
        continue
      }
      children.attr(attr).appendTo(svgElement)
      let textContent = ''
      // 如果text元素具有子元素，且子元素为tspan，则将tspan中的数据提升到text中
      const nestedChildrens = children.children()
      for (const nestedChildren of nestedChildrens) {
        if (nestedChildren.type === 'tspan') {
          textContent += nestedChildren.innerSVG()
        }
      }
      children.attr({
        text: textContent
      })
    }
    element.remove()
  },

  // 自定义处理lineNode节点
  customizeLineNode(element, svgElement) {
    // 移除port元素，并将polyline元素提升到svgElement的子元素
    const attr = element.attr()
    const childrens = element.children()
    for (const children of childrens) {
      if (children.type === 'polyline') {
        children.attr(attr).appendTo(svgElement)
      }
    }
    element.remove()
  },

  // 自定义处理faultNode节点
  customizeFaultNode(element, svgElement) {
    const childrens = element.children()
    const attr = element.attr()
    const id = _.get(attr, 'id', '')
    const name = _.get(attr, 'name', '')
    for (const children of childrens) {
      if (children.type !== 'text') {
        continue
      }
      let textContent = ''
      // 如果text元素具有子元素，且子元素为tspan，则将tspan中的数据提升到text中
      const nestedChildrens = children.children()
      for (const nestedChildren of nestedChildrens) {
        if (nestedChildren.type === 'tspan') {
          textContent += nestedChildren.innerSVG()
          nestedChildren.remove()
        }
      }
      children.attr({
        text: textContent,
        metaType: 'Fault',
        id: id,
        name: name,
        flagId: nanoid(10)
      })
    }
  },

  // 提取节点的样式属性
  extractStyleAttr(element) {
    const attrs = element.attr()
    let styleAttr = _.get(attrs, 'style', '')
    const childrens = element.children()
    for (const children of childrens) {
      const childrenStyle = this.extractStyleAttr(children)
      if (childrenStyle !== '') {
        const styles = _.split(childrenStyle, ';')
        for (const style of styles) {
          const values = _.split(style, ':')
          if (values.length === 2 && styleAttr.indexOf(values[0]) === -1) {
            styleAttr += style + ';'
          }
        }
      }
    }
    return styleAttr
  },

  // 自定义处理通用节点
  customizeCommonNode(component, dataShape, element, svgElement) {
    const nodeConfig = component.$store.getters.getRegisterNode(dataShape)
    const width = nodeConfig.width
    const height = nodeConfig.height
    const nestedChildrens = element.children()
    const styleAttr = this.extractStyleAttr(element)
    let symbolElement = svgElement.select('#' + dataShape)
    if (!symbolElement) {
      symbolElement = svgElement.paper.symbol(0, 0, width, height).attr('id', dataShape)
      for (const nestedChildren of nestedChildrens) {
        const symbolChildren = this.createSymbolChildren(nestedChildren, svgElement)
        symbolChildren.appendTo(symbolElement)
      }

      const symbolHtmlElement = $('body').find('#' + dataShape)
      if (symbolHtmlElement.length === 0) {
        $('body').append(symbolElement.outerSVG())
      }
      symbolElement.toDefs()
    } else {
      // 移除当前元素的子元素
      for (const nestedChildren of nestedChildrens) {
        nestedChildren.remove()
      }
    }

    const childrenAttr = element.attr()
    _.set(childrenAttr, 'style', styleAttr)
    svgElement.paper.use(dataShape).attr({
      x: 0,
      y: 0,
      width: width,
      height: height
    }).attr(childrenAttr).appendTo(element.parent())
    element.remove()
  },

  // 根据element创建symbol的子元素，去掉其中的样式相关属性
  createSymbolChildren(element, svgElement) {
    const styleAttrs = ['style', 'fill', 'stroke', 'stroke-linecap', 'stroke-width']
    const attrs = element.attr()
    const newAttr = {}
    _.forOwn(attrs, function(value, key) {
      if (styleAttrs.indexOf(key) === -1) {
        _.set(newAttr, key, value)
      }
    })
    return svgElement.paper.el(element.type, newAttr)
  },

  handleUndo(graph) {
    graph.history.undo()
  },

  handleRedo(graph) {
    graph.history.redo()
  },

  handleCut(graph) {
    var cells = graph.getSelectedCells()
    graph.cut(cells, {
      deep: true,
      useLocalStorage: true
    })
  },

  handleCopy(graph) {
    var cells = graph.getSelectedCells()
    graph.copy(cells, {
      deep: true,
      useLocalStorage: true
    })
  },

  handlePaste(graph) {
    graph.paste({
      useLocalStorage: true
    })
  },

  handleDelete(graph) {
    var cells = graph.getSelectedCells()
    var vueInstance = new Vue()
    vueInstance.$confirm('确定要删除所选择的节点吗?', '删除确认', {}).then(() => {
      cells.forEach((cell) => {
        graph.removeNode(cell)
      })
      UIUtil.successMessage('节点删除成功')
    })
  },

  canAlign(graph) {
    var vueInstance = new Vue()
    var cells = graph.getSelectedCells()
    if (cells.length < 2) {
      vueInstance.$alert('请选择多余1个的节点进行对齐', '对齐警告')
      return false
    }
    return true
  },

  handleLeftAlign(graph) {
    if (!this.canAlign(graph)) {
      return
    }

    var cells = graph.getSelectedCells()
    var basePos = cells[0].position()
    for (let i = 1; i < cells.length; i++) {
      var cellPos = cells[i].position()
      cells[i].position(basePos.x, cellPos.y)
    }
  },

  handleRightAlign(graph) {
    if (!this.canAlign(graph)) {
      return
    }

    var cells = graph.getSelectedCells()
    var baseSize = cells[0].size()
    var basePos = cells[0].position()
    var xValue = basePos.x + baseSize.width
    for (let i = 1; i < cells.length; i++) {
      var cellPos = cells[i].position()
      var cellSize = cells[i].size()
      cells[i].position(xValue - cellSize.width, cellPos.y)
    }
  },

  handleTopAlign(graph) {
    if (!this.canAlign(graph)) {
      return
    }

    var cells = graph.getSelectedCells()
    var basePos = cells[0].position()
    for (let i = 1; i < cells.length; i++) {
      var cellPos = cells[i].position()
      cells[i].position(cellPos.x, basePos.y)
    }
  },

  handleBottomAlign(graph) {
    if (!this.canAlign(graph)) {
      return
    }

    var cells = graph.getSelectedCells()
    var baseSize = cells[0].size()
    var basePos = cells[0].position()
    var yValue = basePos.y + baseSize.height
    for (let i = 1; i < cells.length; i++) {
      var cellPos = cells[i].position()
      var cellSize = cells[i].size()
      cells[i].position(cellPos.x, yValue - cellSize.height)
    }
  },

  handleCenterAlign(graph) {
    if (!this.canAlign(graph)) {
      return
    }

    var cells = graph.getSelectedCells()
    var baseSize = cells[0].size()
    var basePos = cells[0].position()
    var xValue = basePos.x + baseSize.width / 2
    var yValue = basePos.y + baseSize.height / 2
    for (let i = 1; i < cells.length; i++) {
      var cellSize = cells[i].size()
      cells[i].position(
        xValue - cellSize.width / 2,
        yValue - cellSize.height / 2
      )
    }
  },

  handleEqualWidth(graph) {
    if (!this.canAlign(graph)) {
      return
    }

    var cells = graph.getSelectedCells()
    var baseSize = cells[0].size()
    for (let i = 1; i < cells.length; i++) {
      var cellSize = cells[i].size()
      cells[i].resize(baseSize.width, cellSize.height)
    }
  },

  handleEqualHeight(graph) {
    if (!this.canAlign(graph)) {
      return
    }

    var cells = graph.getSelectedCells()
    var baseSize = cells[0].size()
    for (let i = 1; i < cells.length; i++) {
      var cellSize = cells[i].size()
      cells[i].resize(cellSize.width, baseSize.height)
    }
  },

  handleEqualSize(graph) {
    if (!this.canAlign(graph)) {
      return
    }

    var cells = graph.getSelectedCells()
    var baseSize = cells[0].size()
    for (let i = 1; i < cells.length; i++) {
      cells[i].resize(baseSize.width, baseSize.height)
    }
  },

  handleSelectAll(graph) {
    var nodes = graph.getNodes()
    graph.select(nodes)
  },

  handleUnSelectAll(graph) {
    graph.cleanSelection()
  },

  handleZoomIn(graph) {
    graph.zoom(1.2)
  },

  handleZoomOut(graph) {
    graph.zoom(-1.2)
  },

  handleZoomRestore(graph) {
    graph.zoomTo(1)
  },

  handleShowOrHideGrid(graph, visible) {
    if (visible) {
      graph.showGrid()
    } else {
      graph.hideGrid()
    }
  }
}
